"""--------------------------------------------------------------------------------------------------
Filename:   plotpanel.py
Author:     Chris Chester
Date:       29th August 2013
Description:
    Module containing GUI elements from which the main plot window is composed.
    
--------------------------------------------------------------------------------------------------"""

from pyqtgraph.dockarea import Dock
import pyqtgraph as pg
from pyqtgraph.Qt import QtGui
from config import Modes
        
#===============================================================================
# CLASS: PlotControl(Dock)
#    Container class for the control buttons in the plot window
#===============================================================================
class PlotControl(Dock):
    def __init__(self,name,size, app = None):
        '''
        ==============  =====================================
        **Arguments:**
        name            (string) The name of the dock
        size            ([int,int]) the size of the dock
        app             (Mainapp) mainapp object
        ==============  =====================================
       '''
        
        Dock.__init__(self,name, size=size)
        #Buttons for Control Dock
        self.app = app
        
        self.nextBtn = QtGui.QPushButton('Start')
        self.saveBtn = QtGui.QPushButton('Save Session')
        self.recalBtn = QtGui.QPushButton('Recalibrate')
        self.resetBtn = QtGui.QPushButton('Reset')
        self.saveExitBtn = QtGui.QPushButton('Save and Exit')
        self.pauseBtn = QtGui.QPushButton('Pause')
        self.exitBtn = QtGui.QPushButton('Exit')
        
        self.wCtrl = pg.LayoutWidget() # Control Window
                
        # Sets handlers
        self.exitBtn.clicked.connect(self.app.phdls.exit_plot)
        self.saveBtn.clicked.connect(self.app.phdls.save_sess)
        self.saveExitBtn.clicked.connect(self.app.phdls.save_exit)
        self.pauseBtn.clicked.connect(self.app.phdls.pause)
        self.recalBtn.clicked.connect(self.app.phdls.recalibrate)
        self.resetBtn.clicked.connect(self.app.phdls.target_reset)
        self.nextBtn.clicked.connect(self.app.phdls.next_button)
                        
        self.addWidget(self.wCtrl)
        
        self.__set_properties()
        self.__do_layout()
        
    def __set_properties(self):
        self.nextBtn.setEnabled(False)
        self.saveBtn.setEnabled(False)
        self.pauseBtn.setEnabled(False)
        self.recalBtn.setEnabled(False)
        self.resetBtn.setEnabled(False)
        self.saveExitBtn.setEnabled(True)
        
    def __do_layout(self):
        self.wCtrl.addWidget(self.nextBtn, row=0, col=0)
        self.wCtrl.addWidget(self.pauseBtn, row=1, col=0)
        self.wCtrl.addWidget(self.recalBtn, row=2, col=0)
        
        self.wCtrl.addWidget(self.saveBtn, row=0, col=1)
        self.wCtrl.addWidget(self.resetBtn, row=1, col=1)
        self.wCtrl.addWidget(self.exitBtn, row=2, col=1)

#===============================================================================
# CLASS: PlotConnect(Dock)
#    Container class for the connection buttons in the plot window
#===============================================================================
class PlotConnect(Dock):
    def __init__(self,name,size, app = None):
        '''
        ==============  =====================================
        **Arguments:**
        name            (string) The name of the dock
        size            ([int,int]) the size of the dock
        app             (Mainapp) mainapp object
        ==============  =====================================
       '''
        
        Dock.__init__(self,name, size=size)
        #Buttons for Control Dock
        self.app = app
        
        self.connBtn = QtGui.QPushButton('Connect')
        self.disConnBtn = QtGui.QPushButton('Disconnect')

        
        self.wCtrl = pg.LayoutWidget() # Control Window
                
        # Sets handlers
        self.connBtn.clicked.connect(self.app.phdls.serial_connect)
        self.disConnBtn.clicked.connect(self.app.phdls.serial_disconnect)
                        
        self.addWidget(self.wCtrl)
        
        self.__set_properties()
        self.__do_layout()
        
    def __set_properties(self):
        self.connBtn.setEnabled(True)
        self.disConnBtn.setEnabled(False)
        
    def __do_layout(self):
        self.wCtrl.addWidget(self.connBtn, row=0, col=0)
        self.wCtrl.addWidget(self.disConnBtn, row=1, col=0)
             
#===============================================================================
# CLASS: PlotOptions(Dock)
#    Container class for the options tick boxes in the plot window
#===============================================================================
class PlotOptions(Dock):
    def __init__(self,name,size, app= None):
        '''
        ==============  =====================================
        **Arguments:**
        name            (string) The name of the dock
        size            ([int,int]) the size of the dock
        app             (Mainapp) mainapp object
        ==============  =====================================
       '''
        
        Dock.__init__(self,name, size=size)
        self.app = app
        self.wPlot = pg.LayoutWidget() # check box Window
        
        #Radio buttons for Plot Dock
        self.gridRBtn = QtGui.QCheckBox('Grid')
        self.timeRBtn = QtGui.QCheckBox('Time')
        self.plotRBtn = QtGui.QCheckBox('Plot')
        self.ampRBtn = QtGui.QCheckBox('Amplitude')
    
        self.gridRBtn.setFont(QtGui.QFont('SansSerif', 10))
        self.timeRBtn.setFont(QtGui.QFont('SansSerif', 10))
        self.plotRBtn.setFont(QtGui.QFont('SansSerif', 10))
        self.ampRBtn.setFont(QtGui.QFont('SansSerif', 10))
        
        
        # Handlers
        self.gridRBtn.clicked.connect(self.on_cb_grid)
        self.timeRBtn.clicked.connect(self.on_cb_time)
        self.plotRBtn.clicked.connect(self.on_cb_plot)
        self.ampRBtn.clicked.connect(self.on_cb_ampl)

        self.plotRBtn.setChecked(True)
        
        self.addWidget(self.wPlot)
        
        self.__set_properties()
        self.__do_layout()
        
    def __set_properties(self):
        self.plotRBtn.setChecked(True)
        
    def __do_layout(self):
        self.wPlot.addWidget(self.gridRBtn, row=0, col=0)
        self.wPlot.addWidget(self.plotRBtn, row=0, col=1)
        self.wPlot.addWidget(self.timeRBtn, row=1, col=0)
        self.wPlot.addWidget(self.ampRBtn, row=1, col=1)
        
    def on_cb_grid(self, event):
        '''
        function for grid check box clicked
        '''
        self.app.ctrl.chkbx_ctrl.cb_grid.SetValue(self.gridRBtn.isChecked())
        self.app.plot.draw_grid(self.gridRBtn.isChecked())

    def on_cb_plot(self, event):
        '''
        function for plot check box clicked
        '''
        self.app.ctrl.chkbx_ctrl.cb_plot.SetValue(self.plotRBtn.isChecked())
        self.app.plot.show_plot(self.plotRBtn.isChecked())

    def set_time(self, Value):
        '''
        function for time check box clicked
        ==============  =====================================
        **Arguments:**
        Value           (bool) Whether the button should be on or not
        ==============  =====================================
       '''
        self.timeRBtn.setChecked(Value)
        self.app.ctrl.chkbx_ctrl.cb_time.SetValue(Value)

    def set_amp(self, Value):
        '''
        function for amplitude check box clicked
        ==============  =====================================
        **Arguments:**
        Value           (bool) Whether the button should be on or not
        ==============  =====================================
       '''
        self.ampRBtn.setChecked(Value)
        self.app.ctrl.chkbx_ctrl.cb_ampl.SetValue(Value)
        
    def set_plot(self, Value):
        '''
        function for plot check box clicked
        ==============  =====================================
        **Arguments:**
        Value           (bool) Whether the button should be on or not
        ==============  =====================================
       '''
        self.plotRBtn.setChecked(Value)
        self.app.ctrl.chkbx_ctrl.cb_plot.SetValue(Value)
        
    def set_grid(self, Value):
        '''
        function for grid check box clicked
        ==============  =====================================
        **Arguments:**
        Value           (bool) Whether the button should be on or not
        ==============  =====================================
       '''
        self.gridRBtn.setChecked(Value)
        self.app.ctrl.chkbx_ctrl.cb_grid.SetValue(Value)
        
        
    def on_cb_time(self, event):
        '''
        function for time check box clicked
        '''
        self.app.ctrl.chkbx_ctrl.cb_time.SetValue(self.timeRBtn.isChecked())

    def on_cb_ampl(self, event):
        '''
        function for amplitude check box clicked
        '''
        self.app.ctrl.chkbx_ctrl.cb_ampl.SetValue(self.ampRBtn.isChecked())
        
#===============================================================================
# CLASS: PlotConfig(Dock)
#    Container class for the spin boxes for limits of the target box
#    in the plot window
#===============================================================================
class PlotConfig(Dock):
    def __init__(self,name,size, app= None):
        '''
        ==============  =====================================
        **Arguments:**
        name            (string) The name of the dock
        size            ([int,int]) the size of the dock
        app             (Mainapp) mainapp object
        ==============  =====================================
       '''
        Dock.__init__(self,name, size=size)
        self.wTarRang = pg.LayoutWidget() # Target Ranges window
        self.app = app
        self.config = self.app.cfg
        # Status Label in window
        self.addWidget(self.wTarRang)
        
        self.__set_properties()
        self.__do_layout()
        
    def __set_properties(self):
        self.labelMiss = QtGui.QLabel("Miss Limit")
        self.labelHit = QtGui.QLabel("Hit Limit")
        
        self.mode = self.app.sess_status.mode
        
        if self.mode == Modes.StrCal:
            miss_tot_init = self.config.str_miss_tol
            hit_tot_init = self.config.str_hit_tol 
        elif self.mode == Modes.SklCal:
            miss_tot_init = self.config.miss_tol
            hit_tot_init = self.config.hit_tol
                
        else:
            miss_tot_init=0
            hit_tot_init=0
        
        self.spinMiss = pg.SpinBox(value=miss_tot_init, bounds=[1, None],int=True,step = 1)
        self.spinHit = pg.SpinBox(value=hit_tot_init, bounds=[1, None],int=True,step = 1)
        
        self.spinMiss.sigValueChanged.connect(self.on_miss_spin)
        self.spinHit.sigValueChanged.connect(self.on_hit_spin)
    
    def __do_layout(self):
        self.wTarRang.addWidget(self.labelMiss, row=0, col=0)
        self.wTarRang.addWidget(self.spinMiss, row=0, col=1)
        self.wTarRang.addWidget(self.labelHit, row=1, col=0)
        self.wTarRang.addWidget(self.spinHit, row=1, col=1) 
            
    def on_miss_spin(self, event):
        '''
        Updates the maximum range for the target based on the upper spin box
        '''
        cfg = self.app.cfg
        if self.mode == Modes.StrCal or self.mode == Modes.StrTrl:
            cfg.str_miss_tol = self.spinMiss.value()
            
        else:
            cfg.miss_tol = self.spinMiss.value()
        
    def on_hit_spin(self, event):
        '''
        Updates the minimum range for the target based on the lower spin box
        '''
        cfg = self.app.cfg
        if self.mode == Modes.StrCal or self.mode == Modes.StrTrl:
            cfg.str_hit_tol = self.spinHit.value()
            
        else:
            cfg.hit_tol = self.spinHit.value()


#===============================================================================
# CLASS: PlotStatus(Dock)
#    Container class for the status update box in the plot window
#===============================================================================
class PlotStatus(Dock):
    def __init__(self,name,size, app= None):
        '''
        ==============  =====================================
        **Arguments:**
        name            (string) The name of the dock
        size            ([int,int]) the size of the dock
        app             (Mainapp) mainapp object
        ==============  =====================================
       '''
        Dock.__init__(self,name, size=size)
        self.wTrialStatus = pg.LayoutWidget() # check box Window
        self.app = app
        # Status Label in window
        
        self.addWidget(self.wTrialStatus)
        
        self.__set_properties()
        self.__do_layout()
        
        
    def __set_properties(self):
        self.statusLabel = QtGui.QLabel("Trial Status")
        self.consecHits = QtGui.QLabel("Consecutive Hits")
        self.consecMiss = QtGui.QLabel("Consecutive Misses")
        self.prevRes = QtGui.QLabel("Previous Result")
        
        self.statusLabel.setFont(QtGui.QFont('SansSerif', 10))
        self.consecHits.setFont(QtGui.QFont('SansSerif', 10))
        self.consecMiss.setFont(QtGui.QFont('SansSerif', 10))
        self.prevRes.setFont(QtGui.QFont('SansSerif', 10))
        
    def __do_layout(self):
        self.wTrialStatus.addWidget(self.statusLabel,row = 0,col=0)
        self.wTrialStatus.addWidget(self.consecHits,row = 1,col=0)
        self.wTrialStatus.addWidget(self.consecMiss,row = 2,col = 0)       
        self.wTrialStatus.addWidget(self.prevRes,row = 0,col = 1) 
        
    def set_status(self, s_text):
        '''
        Set the status box text to the input
        
        ==============  =====================================
        **Arguments:**
        s_text            (string) The text to display
        ==============  =====================================
        '''
        self.statusLabel.setText(s_text)
        
    def set_hits(self, s_text):
        '''
        Set the consecutive hits text to the input
        
        ==============  =====================================
        **Arguments:**
        s_text          (string) Number of hits
        ==============  =====================================
        '''
        self.consecHits.setText(s_text)
        
    def set_miss(self, s_text):
        '''
        Set the consecutive misses text to the input
        
        ==============  =====================================
        **Arguments:**
        s_text          (string) Number of misses
        ==============  =====================================
        '''
        self.consecMiss.setText(s_text)
        
    def set_prev_result(self, s_text):
        '''
        Set the previous result text to the input
        
        ==============  =====================================
        **Arguments:**
        s_text          (string) Previous result
        ==============  =====================================
        '''
        self.prevRes.setText(s_text)

#===============================================================================
# CLASS: PlotRange(Dock)
#    Container class for the spin boxes for limits of the target box
#    in the plot window
#===============================================================================
class PlotRange(Dock):
    def __init__(self,name,size, app= None):
        '''
        ==============  =====================================
        **Arguments:**
        name            (string) The name of the dock
        size            ([int,int]) the size of the dock
        app             (Mainapp) mainapp object
        ==============  =====================================
       '''
        Dock.__init__(self,name, size=size)
        self.wTarRang = pg.LayoutWidget() # Target Ranges window
        self.app = app
        
        # Status Label in window
        self.addWidget(self.wTarRang)
        
        self.__set_properties()
        self.__do_layout()
        
    def __set_properties(self):
        self.labelUpper = QtGui.QLabel("Upper Limit")
        self.labelLower = QtGui.QLabel("Lower Limit")
        self.spinUpper = pg.SpinBox(value=self.app.cfg.init_max_range, bounds=[0, None],int=True,step = 1)
        self.spinLower = pg.SpinBox(value=self.app.cfg.init_min_range, bounds=[0, None],int=True,step = 1)
        
        self.spinUpper.sigValueChanged.connect(self.on_upper_spin)
        self.spinLower.sigValueChanged.connect(self.on_lower_spin)

    
    def __do_layout(self):
        self.wTarRang.addWidget(self.labelUpper, row=0, col=0)
        self.wTarRang.addWidget(self.spinUpper, row=0, col=1)
        self.wTarRang.addWidget(self.labelLower, row=1, col=0)
        self.wTarRang.addWidget(self.spinLower, row=1, col=1) 
            
    def on_upper_spin(self, event):
        '''
        Updates the maximum range for the target based on the upper spin box
        '''
        cfg = self.app.cfg
        cfg.upper_limit = self.spinUpper.value()/100.0
        range_max = [cfg.trial_len - cfg.x_margin, cfg.upper_limit*self.app.sess_status.baseline]
        self.app.plot.tfactory.set_range_max(range_max)
        
    def on_lower_spin(self, event):
        '''
        Updates the minimum range for the target based on the lower spin box
        '''
        cfg = self.app.cfg
        cfg.lower_limit = self.spinLower.value()/100.0
        range_min = [cfg.x_margin, cfg.lower_limit*self.app.sess_status.baseline]
        self.app.plot.tfactory.set_range_min(range_min)

#===============================================================================
# CLASS: PlotBase(Dock)
#    Container class for the spin boxes for limits of the target box
#    in the plot window
#===============================================================================
class PlotBase(Dock):
    def __init__(self,name,size, app= None):
        '''
        ==============  =====================================
        **Arguments:**
        name            (string) The name of the dock
        size            ([int,int]) the size of the dock
        app             (Mainapp) mainapp object
        ==============  =====================================
       '''
        Dock.__init__(self,name, size=size)
        self.wTarRang = pg.LayoutWidget() # Target Ranges window
        self.app = app
        
        # Status Label in window
        self.addWidget(self.wTarRang)
        
        self.__set_properties()
        self.__do_layout()
        
    def __set_properties(self):
        self.labelUpper = QtGui.QLabel("Baseline")
        self.spinUpper = pg.SpinBox(value=100, bounds=[0, None],int=True,step = 1)
        
        self.spinUpper.sigValueChanged.connect(self.on_upper_spin)

    
    def __do_layout(self):
        self.wTarRang.addWidget(self.labelUpper, row=0, col=0)
        self.wTarRang.addWidget(self.spinUpper, row=0, col=1)
            
    def on_upper_spin(self, event):
        '''
        Updates the maximum range for the target based on the upper spin box
        '''
        cfg = self.app.cfg
        self.app.sess_status.str_target = self.spinUpper.value()/100.0 *self.app.sess_status.baseline
        

        
# End of plotpanel.py
